9장 모던 리액트 개발 도구로 개발 및 배포 환경 구축하기
1. Next.js로 리액트 개발 환경 구축하기
1. create-next-app 없이 하나씩 구축하기
보통 명령어를 사용하거나 IDE 프로젝트 생성을 통해 기본 환경을 구축하는데 애플리케이션을 온전히 이해하기 위해 package.json
부터 차례대로 필요한 파일을 직접 만들어 보는 것이 좋다.
npm init
package.json 파일을 생성한다.
npm i react react-dom next
핵심 라이브러리를 설치한다.
npm i @types/node @types/react @types/react-dom eslint eslint-config-next typescript --save-dev
의존 패키지를 설치한다.
2. tsconfig.json 작성하기
"$schema": "https://json.schemastore.org/tsconfig.json",
"compilerOptions": {
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"baseUrl": "src",
"paths": {
"#pages/*": ["pages/*"],
"#hooks/*": ["hooks/*"],
"#types/*": ["types/*"],
"#components/*": ["components/*"],
"#utils/*": ["utils/*"]
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
"exclude": ["node_modules"]
}
-
compilerOptions: 타입스크립트를 자바스크립트로 컴파일할 때 사용하는 옵션이다.
-
target: 타입스크립트가 변환을 목표로 하는 언어의 버전을 의미한다.
-
lib: 해당 환경 라이브러리를 포함하겠다고 정의하는 것을 의미한다.
-
allowJs: 타입스크립트가 자바스크립트 파일 또한 컴파일할지를 결정한다.
-
skipLibCheck: 라이브러리에서 제공하는 d.ts에 대한 검사 여부를 결정한다.
-
strict: 타입스크립트 컴파일러의 엄격 모드를 제어한다
-
forceConsistentCasingInFileNames: 파일 이름의 대소문자를 구분하도록 강제한다
-
noEmit: 컴파일을 하지 않고, 타입 체크만 한다. Next.js는
swc
가 타입스크립트 파일을 매우 빠른 속도로 컴파일 한다. -
esModuleInterop: CommonJS 방식으로 보낸 모듈을 ES 모듈 방식의 import로 가져올 수 있게 해준다
-
module: 모듈 시스템을 설정한다. commonjs는
require
를 사용하고, esnext 는import
를 사용한다. -
moduleResolution: 모듈을 해석하는 방식을 설정한다.
-
resolveJsonModule: JSON 파일을 import할 수 있게 해준다. 이 옵션을 켜두면 allowJs 옵션도 자동으로 켜진다
-
isolatedModules: 다른 모듈 시스템과 연계되지 않고 단독으로 있는 파일의 생성을 막기 위한 옵션이다.
-
jsx: .tsx 파일 내부에 있는 JSX를 어떻게 컴파일할지 설정한다
-
incremental :타입스크립트에서 마지막 컴파일 정보를.tsbuildinfo 파일 형태로 만들어 디스크에 저장한다.
-
baseUrl: 모듈을 찾을 때 기준이 되는 디렉터리를 지정한다.
-
paths: 상대 경로에 별칭을 지정해 사용하기 편하게 만들 수 있다.
#
나$
같은 특수문자 접두사와 함께 자주 사용된다 -
include: 타입스크립트 컴파일 대상에서 포함시킬 파일 목록을 의미한다.
-
exclude: 타입스크립트 컴파일 대상에서 제외시킬 파일 목록을 의미한다.
3. next.config.js 작성하기
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
poweredByHeader: false,
eslint: {
ignoreDuringBuilds: true,
},
}
module.exports = nextConfig
-
reactStrictMode: 리액트의 엄격 모드를 활성화한다.
-
poweredByHeader: 일반적으로 보안 취약점으로 취급되는 X-Powered-By 헤더를 제거한다
-
eslint.ignoreDuringBuilds: 빠른 빌드를 위해 빌드 시 ESLint를 무시한다.
4. ESLint와 Prettier 설정하기
npm i @titicaca/eslint-config-triple --save-dev
const path = require('path')
const createConfig = require('@titicaca/eslint-config-triple/create-config')
const { extends: extendConfigs, overrides } = createConfig({
type: 'frontend',
project: path.resolve(__dirname, './tsconfig.json'),
})
module.exports = {
extends: [...extendConfigs, 'next/core-web-vitals'],
overrides,
}
잠재적 문제 확인을 위한eslint-config-next
와 코드 스타일링을 위한 eslint-config-triple
이 함께 작동하게 하려면 별도의 설정이 필요하다.
5. 애플리케이션 코드 작성
-
pages: Next.js에서 예약어로 지정해 두고 사용하는 폴더로, 이 폴더 하위의 내용은 모두 실제 라우터가 된다.
-
components: 페이지 내부에서 사용하는 컴포넌트를 모아둔 폴더다.
-
hooks: 직접 만든 훅을 모아둔 폴더다.
-
types: 서버 응답 타입 등 공통으로 사용하는 타입을 모아둔 폴더다.
-
utils: 애플리케이션 전역에서 공용으로 사용하는 유틸성 파일을 모아둔 폴더다.
2. 깃허브 100% 활용하기
1. 깃허브 액션으로 CI 환경 구축하기
1. CI (Continuous Integration)
- 지속적 통합이란 뜻으로, 중앙 저장소에서 코드의 변화가 있을 때마다 전체 정합성을 확인하기 위한 작업을 자동으로 실행한다.
2. CD (Continuous Delivery / Continuous Deployment)
- 지속적 전달 : CI 이후 자동으로 배포 준비를 완료해주며 개발자의 승인 후 배포된다.
- 지속적 배포: CI 이후 테스트를 통과하면 자동으로 별도의 승인 없이 배포된다.
2. 깃허브 액션의 기본 개념
- runner: 파일로 작성된 깃허브 액션이 실행되는 서버를 의미한다.
- action: 러너에서 실행되는 하나의 작업 단위를 의미한다. yaml 파일로 작성된 내용을 하나의 액션으로 볼 수 있다
- event: 깃허브 액션의 실행을 일으키는 이벤트를 의미한다. pull request, push 등이 해당된다.
- jobs: 하나의 러너에서 실행되는 여러 스텝의 모음을 의미한다.
- steps: 잡 내부에서 일어나는 하나하나의 작업을 의미한다.
3. 깃허브 액션 작성하기
저장소 루트에 .github/workflows 폴더를 생성하고 build.yaml 파일을 작성한다.
name: chapter7 build
run-name: ${{ github.actor }} has been added new commit.
on:
push:
branches-ignore:
- 'main'
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 16
- name: 'Install dependencies'
working-directory: ./chapter7/my-app
run: npm ci
- name: 'Build'
working-directory: ./chapter7/my-app
run: npm run build
-
name: 액션을 구분하는 데 필요한 이름을 지정할 수 있다.
-
run-name: 액션 실행을 구별하는 타이틀 명이다. 누가 어떤 액션을 트리거 했는지 정도를 구별한다.
-
on: 필수 값으로, 언제 해당 액션을 실행할지를 정의한다. 깃허브 문서에 자세한 내용이 있다.
-
jobs: 필수 값으로, 해당 액션에서 수행할 잡을 의미한다. 여러 개를 설정하면 병렬로 실행된다.
-
브랜치 보호 규칙: 머지 하기 전 수행해야 하는 액션을 설정할 수 있다. 해당 액션이 실패하면 머지할 수 없다.
4. 직접 작성하지 않고 유용한 액션과 깃허브 앱 가져다 쓰기
깃허브에서 제공하는 기본 액션들과 Marketplaces 서비스를 이용해 다른 사용자가 만든 액션을 사용할 수 있다.
5. Dependabot 사용하기
# .github/dependabot.yml
version: 2
updates:
- package-ecosystem: "npm" # 사용할 패키지 관리자 (npm, yarn 등)
directory: "/" # 의존성 파일이 위치한 디렉터리 (대개 루트 디렉터리)
schedule:
interval: "weekly" # 업데이트 확인 주기 (daily, weekly, monthly)
ignore:
- dependency-name: "express" # 특정 패키지는 무시하고 업데이트 하지 않도록 설정
versions: ["4.x.x"]
-
해당 루트 디렉토리의 의존성 파일을 매주 확인하고 패키지의 버전 업데이트를 막을 수 있다.
-
의존성 업데이트가 필요하면 자동으로 풀 리퀘스트를 생성하고 업데이트 된 파일의 의존성 버전과 해결된 취약점이 포함된다.
3. 리액트 애플리케이션 도커라이즈하기
1. 리액트 앱을 도커라이즈하는 방법
애플리케이션을 도커 이미지로 만들어 신속하게 구축해 배포할 수 있는 상태로 준비하는 것을 도커라이즈라고 한다.
1. 용어
-
이미지: 컨테이너를 만드는 데 사용하는 템플릿을 의미한다. 도커 파일을 빌드하면 이미지를 만들 수 있다.
-
컨테이너: 이미지를 실행한 상태이다. 이미지가 목표하는 운영체제, 파일 시스템. 네트워크 등을 할 당해 실행시킬 수 있는 독립된 공간이다.
-
도커 파일: 어떤 이미지 파일을 만들지 정의하는 파일이다.
-
태그: 이미지를 식별할 수 있는 레이블 값이다.
이름:태그명
형태로 구성되어있다. -
리포지터리: 태그로 지정된 이미지가 모여있는 저장소다.
-
레지스트리:
Docker Hub
등이 있으며 리포지터리에 접근할 수 있께 해주는 서비스다.
2. create-next-app을 위한 Dockerfile 작성하기
FROM node:18.12.0-alpine3.16 as deps
WORKDIR /app
COPY package.json ./package.json
COPY package-lock.json ./package-lock.json
RUN npm ci
프로젝트에 필요한 노드 모듈을 생성한다.
FROM node:18.12.0-alpine3.16 as build
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . ./
RUN npm run build
앞에서 생성한 노드 모듈을 복사해서 사용하고 프로젝트를 빌드한다.
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
swcMinify: true,
// 이 옵션을 추가
output: 'standalone',
}
module.exports = nextConfig
Next.js가 프로덕션 실행에 필요한 파일을 모아서 준비해준다.
FROM node:18.12.0-alpine3.16 as runner
COPY --from=build /app/public ./public
COPY --from=build /app/.next/standalone ./
COPY --from=build /app/.next/static ./.next/static
EXPOSE 3000
ENTRYPOINT ["node", "server.js"]
runner 단계를 만들어서 standalone으로 만들어진 Next.js를 실행한다.
docker build . -t next:test
이미지를 빌드하고 도커 데스크톱에서 실행할 수 있다.